﻿#include "ZCommon.h"
#include "ZString.h"

#ifdef WIN32
#include <Windows.h>
#endif

namespace ZuiLib
{

#ifdef WIN32
std::wstring Utf8ToUnicode(const std::string& str)
{
    int  len = 0;
    len = str.length();
    int  unicodeLen = ::MultiByteToWideChar(CP_UTF8,
        0,
        str.c_str(),
        -1,
        NULL,
        0);
    wchar_t *  pUnicode;
    pUnicode = (wchar_t*)zmalloc(sizeof(wchar_t)*(unicodeLen + 1));
    memset(pUnicode, 0, (unicodeLen + 1) * sizeof(wchar_t));
    ::MultiByteToWideChar(CP_UTF8,
        0,
        str.c_str(),
        -1,
        (LPWSTR)pUnicode,
        unicodeLen);
    std::wstring  rt;
    rt = (wchar_t*)pUnicode;
		zfree(pUnicode);
    return  rt;
}

std::string UnicodeToUtf8(const std::wstring& str)
{
    char*     pElementText;
    int    iTextLen;
    // wide char to multi char
    iTextLen = WideCharToMultiByte(CP_UTF8,
        0,
        str.c_str(),
        -1,
        NULL,
        0,
        NULL,
        NULL);
    pElementText = (char*)zmalloc(iTextLen + 1);
    memset((void*)pElementText, 0, sizeof(char) * (iTextLen + 1));
    ::WideCharToMultiByte(CP_UTF8,
        0,
        str.c_str(),
        -1,
        pElementText,
        iTextLen,
        NULL,
        NULL);
    std::string strText;
    strText = pElementText;
    zfree(pElementText);
    return strText;
}
#endif

// Convert UTF-8 to 32-bits character, process single character input.
// Based on stb_from_utf8() from github.com/nothings/stb/
// We handle UTF-8 decoding error by skipping forward.
int ZTextCharFromUtf8(ZWChar* out_char, const char* in_text, const char* in_text_end)
{
    unsigned int c = (unsigned int)-1;
    const unsigned char* str = (const unsigned char*)in_text;
    if (!(*str & 0x80))
    {
        c = (unsigned int)(*str++);
        *out_char = c;
        return 1;
    }
    if ((*str & 0xe0) == 0xc0)
    {
        *out_char = 0xFFFD; // will be invalid but not end of string
        if (in_text_end && in_text_end - (const char*)str < 2) return 1;
        if (*str < 0xc2) return 2;
        c = (unsigned int)((*str++ & 0x1f) << 6);
        if ((*str & 0xc0) != 0x80) return 2;
        c += (*str++ & 0x3f);
        *out_char = c;
        return 2;
    }
    if ((*str & 0xf0) == 0xe0)
    {
        *out_char = 0xFFFD; // will be invalid but not end of string
        if (in_text_end && in_text_end - (const char*)str < 3) return 1;
        if (*str == 0xe0 && (str[1] < 0xa0 || str[1] > 0xbf)) return 3;
        if (*str == 0xed && str[1] > 0x9f) return 3; // str[1] < 0x80 is checked below
        c = (unsigned int)((*str++ & 0x0f) << 12);
        if ((*str & 0xc0) != 0x80) return 3;
        c += (unsigned int)((*str++ & 0x3f) << 6);
        if ((*str & 0xc0) != 0x80) return 3;
        c += (*str++ & 0x3f);
        *out_char = c;
        return 3;
    }
    if ((*str & 0xf8) == 0xf0)
    {
        *out_char = 0xFFFD; // will be invalid but not end of string
        if (in_text_end && in_text_end - (const char*)str < 4) return 1;
        if (*str > 0xf4) return 4;
        if (*str == 0xf0 && (str[1] < 0x90 || str[1] > 0xbf)) return 4;
        if (*str == 0xf4 && str[1] > 0x8f) return 4; // str[1] < 0x80 is checked below
        c = (unsigned int)((*str++ & 0x07) << 18);
        if ((*str & 0xc0) != 0x80) return 4;
        c += (unsigned int)((*str++ & 0x3f) << 12);
        if ((*str & 0xc0) != 0x80) return 4;
        c += (unsigned int)((*str++ & 0x3f) << 6);
        if ((*str & 0xc0) != 0x80) return 4;
        c += (*str++ & 0x3f);
        // utf-8 encodings of values used in surrogate pairs are invalid
        if ((c & 0xFFFFF800) == 0xD800) return 4;
        *out_char = c;
        return 4;
    }
    *out_char = 0;
    return 0;
}

int ZTextStrFromUtf8(ZWChar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_text_remaining)
{
    ZWChar* buf_out = buf;
    ZWChar* buf_end = buf + buf_size;
    while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
    {
        ZWChar c;
        in_text += ZTextCharFromUtf8(&c, in_text, in_text_end);
        if (c == 0)
            break;
        //if (c < 0x10000)    // FIXME: Losing characters that don't fit in 2 bytes
            *buf_out++ = (ZWChar)c;
    }
    *buf_out = 0;
    if (in_text_remaining)
        *in_text_remaining = in_text;
    return (int)(buf_out - buf);
}

int ZTextCountCharsFromUtf8(const char* in_text, const char* in_text_end)
{
    int char_count = 0;
    while ((!in_text_end || in_text < in_text_end) && *in_text)
    {
        ZWChar c;
        in_text += ZTextCharFromUtf8(&c, in_text, in_text_end);
        if (c == 0)
            break;
        //if (c < 0x10000)
            char_count++;
    }
    return char_count;
}

// Based on stb_to_utf8() from github.com/nothings/stb/
inline int ZTextCharToUtf8(char* buf, int buf_size, unsigned int c)
{
    if (c < 0x80)
    {
        buf[0] = (char)c;
        return 1;
    }
    if (c < 0x800)
    {
        if (buf_size < 2) return 0;
        buf[0] = (char)(0xc0 + (c >> 6));
        buf[1] = (char)(0x80 + (c & 0x3f));
        return 2;
    }
    if (c >= 0xdc00 && c < 0xe000)
    {
        return 0;
    }
    if (c >= 0xd800 && c < 0xdc00)
    {
        if (buf_size < 4) return 0;
        buf[0] = (char)(0xf0 + (c >> 18));
        buf[1] = (char)(0x80 + ((c >> 12) & 0x3f));
        buf[2] = (char)(0x80 + ((c >> 6) & 0x3f));
        buf[3] = (char)(0x80 + ((c ) & 0x3f));
        return 4;
    }
    else if (c < 0x10000)
    {
        if (buf_size < 3) return 0;
        buf[0] = (char)(0xe0 + (c >> 12));
        buf[1] = (char)(0x80 + ((c>> 6) & 0x3f));
        buf[2] = (char)(0x80 + ((c ) & 0x3f));
        return 3;
    }
    else
    {
        if (buf_size < 4) return 0;
        buf[0] = (char)(((c & 0x1c0000) >> 18) | 0xf0);
        buf[1] = (char)(((c & 0x3f000) >> 12) | 0x80);
        buf[2] = (char)(((c & 0xfc0) >> 6) | 0x80);
        buf[3] = (char)((c & 0x3f) | 0x80);
        return 4;
    }
}

inline int ZTextCountUtf8BytesFromChar(unsigned int c)
{
    if (c < 0x80) return 1;
    if (c < 0x800) return 2;
    if (c >= 0xdc00 && c < 0xe000) return 0;
    if (c >= 0xd800 && c < 0xdc00) return 4;
    if (c > 0x10000) return 4;
    return 3;
}

int ZTextStrToUtf8(char* buf, int buf_size, const ZWChar* in_text, const ZWChar* in_text_end)
{
    char* buf_out = buf;
    const char* buf_end = buf + buf_size;
    while (buf_out < buf_end-1 && (!in_text_end || in_text < in_text_end) && *in_text)
    {
        unsigned int c = (unsigned int)(*in_text++);
        if (c < 0x80)
            *buf_out++ = (char)c;
        else
            buf_out += ZTextCharToUtf8(buf_out, (int)(buf_end-buf_out-1), c);
    }
    *buf_out = 0;
    return (int)(buf_out - buf);
}

int ZTextCountUtf8BytesFromStr(const ZWChar* in_text, const ZWChar* in_text_end)
{
    int bytes_count = 0;
    while ((!in_text_end || in_text < in_text_end) && *in_text)
    {
        unsigned int c = (unsigned int)(*in_text++);
        if (c < 0x80)
            bytes_count++;
        else
            bytes_count += ZTextCountUtf8BytesFromChar(c);
    }
    return bytes_count;
}

/* The mixing step */
#define mix(a,b,c) \
{ \
	a=a-b;  a=a-c;  a=a^(c>>13); \
	b=b-c;  b=b-a;  b=b^(a<<8);  \
	c=c-a;  c=c-b;  c=c^(b>>13); \
	a=a-b;  a=a-c;  a=a^(c>>12); \
	b=b-c;  b=b-a;  b=b^(a<<16); \
	c=c-a;  c=c-b;  c=c^(b>>5);  \
	a=a-b;  a=a-c;  a=a^(c>>3);  \
	b=b-c;  b=b-a;  b=b^(a<<10); \
	c=c-a;  c=c-b;  c=c^(b>>15); \
}

typedef  unsigned long int  u4;   /* unsigned 4-byte type */
typedef  unsigned     char  u1;   /* unsigned 1-byte type */




//返回字符串
uint32_t zhash(register const unsigned char *k,uint32_t length,uint32_t initval)
{
	register uint32_t a,b,c;  /* the internal state */
	uint32_t          len;    /* how many key bytes still need mixing */

	/* Set up the internal state */
	len = length;
	a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
	c = initval;         /* variable initialization of internal state */

	/*---------------------------------------- handle most of the key */
	while (len >= 12)
	{
		a=a+(k[0]+((u4)k[1]<<8)+((u4)k[2]<<16) +((u4)k[3]<<24));
		b=b+(k[4]+((u4)k[5]<<8)+((u4)k[6]<<16) +((u4)k[7]<<24));
		c=c+(k[8]+((u4)k[9]<<8)+((u4)k[10]<<16)+((u4)k[11]<<24));
		mix(a,b,c);
		k = k+12; len = len-12;
	}

	/*------------------------------------- handle the last 11 bytes */
	c = c+length;
	switch(len)              /* all the case statements fall through */
	{
	case 11: c=c+((u4)k[10]<<24);
	case 10: c=c+((u4)k[9]<<16);
	case 9 : c=c+((u4)k[8]<<8);
		/* the first byte of c is reserved for the length */
	case 8 : b=b+((u4)k[7]<<24);
	case 7 : b=b+((u4)k[6]<<16);
	case 6 : b=b+((u4)k[5]<<8);
	case 5 : b=b+k[4];
	case 4 : a=a+((u4)k[3]<<24);
	case 3 : a=a+((u4)k[2]<<16);
	case 2 : a=a+((u4)k[1]<<8);
	case 1 : a=a+k[0];
		/* case 0: nothing left to add */
	}
	mix(a,b,c);
	return c;
}

char hCharArray[]={
	'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
	'0','1','2','3','4','5','6','7','8','9','~','`','!','@',';','$','%','^','&','(',')','-','+','_','[',']','{','}',',','_'
};

void zhashText(register const u1 *k,u4 length,u4 initval,char out[64])
{
	register uint32_t a,b,c;  /* the internal state */
	uint32_t          len;    /* how many key bytes still need mixing */

	/* Set up the internal state */
	len = length;
	a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
	c = initval;         /* variable initialization of internal state */

	/*---------------------------------------- handle most of the key */
	while (len >= 12)
	{
		a=a+(k[0]+((u4)k[1]<<8)+((u4)k[2]<<16) +((u4)k[3]<<24));
		b=b+(k[4]+((u4)k[5]<<8)+((u4)k[6]<<16) +((u4)k[7]<<24));
		c=c+(k[8]+((u4)k[9]<<8)+((u4)k[10]<<16)+((u4)k[11]<<24));
		mix(a,b,c);
		k = k+12; len = len-12;
	}

	/*------------------------------------- handle the last 11 bytes */
	c = c+length;
	switch(len)              /* all the case statements fall through */
	{
	case 11: c=c+((u4)k[10]<<24);
	case 10: c=c+((u4)k[9]<<16);
	case 9 : c=c+((u4)k[8]<<8);
		/* the first byte of c is reserved for the length */
	case 8 : b=b+((u4)k[7]<<24);
	case 7 : b=b+((u4)k[6]<<16);
	case 6 : b=b+((u4)k[5]<<8);
	case 5 : b=b+k[4];
	case 4 : a=a+((u4)k[3]<<24);
	case 3 : a=a+((u4)k[2]<<16);
	case 2 : a=a+((u4)k[1]<<8);
	case 1 : a=a+k[0];
		/* case 0: nothing left to add */
	}

	int pos=0;
	//转换abc为字符串
	while(a>0)
	{
		out[pos++]=hCharArray[a%56];
		a=a/56;
	}

	while(b>0)
	{
		out[pos++]=hCharArray[b%56];
		b=b/56;
	}

	while(c>0)
	{
		out[pos++]=hCharArray[c%56];
		c=c/56;
	}
	out[pos]='\0';
}


ZString zstrhash(const char* text, int len)
{
	char out[64];
	if (len < 0)
		len = strlen(text);
	zhashText((const u1 *)text, len,0x46A2F8E9,out);
	return ZString(out);
}


}//namespace



